#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#define NUM 10
template<class T>
class block_queue
{
  public:
    bool isfull()
    {
      return q.size()==cap;
    }
    
    bool isempty()
    {
      return q.empty();
    }
    
    block_queue(int _cap=NUM)
      :cap(_cap)
    {
      pthread_cond_init(&full,nullptr);
      pthread_cond_init(&empty,nullptr);
      pthread_mutex_init(&lock,nullptr);
    }

    ~block_queue()
    {
      pthread_cond_destroy(&full);
      pthread_cond_destroy(&empty);
      pthread_mutex_destroy(&lock);
    }
    
    void push(const T& in)
    {
      pthread_mutex_lock(&lock);
      while(isfull())
      {
        pthread_cond_wait(&full,&lock);
      }
      q.push(in);
      if(q.size()>=cap/2)
      {
       printf("数据已经很多了，消费者快来消费吧\n"); 
        pthread_cond_signal(&empty);
      }
      pthread_mutex_unlock(&lock);
    }

    void pop(T& out)
    {
      pthread_mutex_lock(&lock);
      while(isempty())
      {
        pthread_cond_wait(&empty,&lock);
      }
      out=q.front();
      q.pop();
      if(q.size()<cap/2)
      {
       printf("数据快没有了，生产者快来生产吧\n"); 
        pthread_cond_signal(&full);
      }
      pthread_mutex_unlock(&lock);
    }

  private:
   int cap;
   pthread_mutex_t lock;
   std::queue<T> q;
   pthread_cond_t full;
   pthread_cond_t empty;
};
